package cn.tang.tframe.common.utils.lang;

import cn.tang.tframe.common.annotation.BeanOrder;
import cn.tang.tframe.common.annotation.QtSpi;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author tanghc 
 */
public abstract class SpiUtils {

    private static ConcurrentHashMap<Class,Boolean> clazzInitMap = new ConcurrentHashMap<>();
    private static ConcurrentHashMap<Class,List> clazzMap = new ConcurrentHashMap<>();
    private static ConcurrentHashMap<String,Object> spiMap = new ConcurrentHashMap<>();

	public static <T> void init(Class<T> clazz){
        Boolean isInit = clazzInitMap.get(clazz);
        if(isInit != null && isInit){
            return ;
        }
		ServiceLoader<T> load = ServiceLoader.load(clazz);
        Set<T> set = new HashSet<>();
		if(null != load){
			CollectionUtils.addAll(set,load.iterator());
            TreeMap<Integer,T> beans = new TreeMap<>();
            if(null != set){
                for(T t :set){
                    BeanOrder annotation = AnnotationUtils.findAnnotation(t.getClass(), BeanOrder.class);
                    int order = 1000;
                    if(null != annotation){
                        order = annotation.order();
                    }
                    beans.put(order,t);
                    QtSpi qtSpi = AnnotationUtils.findAnnotation(t.getClass(), QtSpi.class);
                    String clazzName = "";
                    if(null != qtSpi){
                        clazzName = qtSpi.value();
                    }
                    if(StringUtils.isBlank(clazzName)){
                        clazzName = t.getClass().getSimpleName();
                    }
                    spiMap.put(clazzName,t);
                }
            }
            Collection<T> values = beans.values();
            if(null != values){
                clazzMap.put(clazz,new ArrayList(values));
            }
		}
        clazzInitMap.put(clazz, Boolean.TRUE);
        return ;
	}
	public static <T> List<T> listSpi(Class<T> clazz){
        init(clazz);
        List list = clazzMap.get(clazz);
        return list;
	}
	public static <T> T getSpiBean(String name,Class<T> clazz){
        init(clazz);
        T o = (T)spiMap.get(name);
        if(null == o){
            List<T> ts = listSpi(clazz);
            if(CollectionUtils.isNotEmpty(ts)){
                return ts.get(0);
            }
        }
        return o;
	}
}
